package dao

import (
	"common/biz"
	"common/logs"
	"common/utils"
	"context"
	"core/models/db"
	"core/models/entity"
	"core/repo"
	"errors"
	"fmt"
	"framework/msError"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"gorm.io/gorm"
	"hall/models/request"
	"strconv"
	"time"
)

type UserDao struct {
	repo *repo.Manager
	base *BaseDao
}

func (d *UserDao) FindUserByUid(ctx context.Context, uid uint) (*db.User, error) {
	user := new(db.User)
	d.repo.DB.Client.WithContext(ctx).Model(user).Where("id=?", uid).First(user)
	if user == nil {
		return nil, errors.New("无查询到账号")
	}
	return user, nil
}

func (d *UserDao) UpdateUserAddressByUid(ctx context.Context, user *entity.User) error {
	//db := d.repo.Mongo.Db.Collection("user")
	//_, err := db.UpdateOne(ctx, bson.M{
	//	"uid": user.Uid,
	//}, bson.M{
	//	"$set": bson.M{
	//		"address":  user.Address,
	//		"location": user.Location,
	//	},
	//})
	//return err
	return nil
}

func (d *UserDao) UpRoleID(ctx context.Context, uid, roleID uint) error {
	user := new(db.User)
	return d.repo.DB.Client.WithContext(ctx).Model(user).Where("id=?", uid).Update("role_id", roleID).Error
}

func (d *UserDao) MongoFindUserByUid(ctx context.Context, uid uint) (*entity.User, error) {
	collection := d.repo.Mongo.Db.Collection("user")
	singleResult := collection.FindOne(ctx, bson.D{
		{"uid", uid},
	})
	user := new(entity.User)
	err := singleResult.Decode(user)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, nil
		}
		return nil, err
	}
	return user, nil
}

func (d *UserDao) MongoUserInsert(ctx context.Context, user *entity.User) error {
	collection := d.repo.Mongo.Db.Collection("user")
	_, err := collection.InsertOne(ctx, user)
	return err
}

func (d *UserDao) UpRealName(ctx context.Context, uid uint, id uint) error {
	user := new(db.User)
	return d.repo.DB.Client.WithContext(ctx).Model(user).Where("id=?", uid).Update("real_id", id).Error
}

func (d *UserDao) GetUID(ctx context.Context, token string) uint {
	var uid uint
	user := new(db.User)
	d.repo.DB.Client.WithContext(ctx).Model(user).Where("token=?", token).Select("id").Scan(&uid)
	return uid
}

func (d *UserDao) GetUserOfReal(ctx context.Context, uid uint) *db.UserHasOneRealOfWallet {
	user := new(db.UserHasOneRealOfWallet)
	d.repo.DB.Client.WithContext(ctx).Model(db.User{}).Where("id=?", uid).
		Preload("Role").
		Preload("Real").
		Preload("Wallet").
		First(user)
	return user
}

func (d *UserDao) AddWallet(ctx context.Context, wallet *db.UserHfWallet) error {
	err := d.repo.DB.Client.WithContext(ctx).Model(wallet).Create(wallet).Error
	if err != nil {
		return err
	}
	user := new(db.User)
	_, err = d.repo.Mongo.Db.Collection("user").
		UpdateOne(ctx, bson.D{
			{"uid", wallet.UID},
		}, bson.M{"$set": bson.D{
			{"wallet_id", wallet.ID},
		}})
	if err != nil {
		return err
	}
	err = d.repo.DB.Client.WithContext(ctx).Model(user).Where("id=?", wallet.UID).Update("wallet_id", wallet.ID).Error
	if err != nil {
		return err
	}
	return nil
}

func (d *UserDao) AddWalletLog(ctx context.Context, log *db.WalletPayLog) error {
	return d.repo.DB.Client.WithContext(ctx).Model(log).Create(log).Error
}

func (d *UserDao) UpRealOsStatus(ctx context.Context, uid uint) error {
	return d.repo.DB.Client.WithContext(ctx).Model(db.UserRealName{}).Where("uid=?", uid).Update("status", true).Error
}

func (d *UserDao) UpRealOsOrderNo(ctx context.Context, uid uint, orderNo string) error {
	return d.repo.DB.Client.WithContext(ctx).Model(db.UserRealName{}).Where("uid=?", uid).Update("order_no", orderNo).Error
}

func (d *UserDao) AddHfNotifyLog(ctx context.Context, log *db.HfNotifyLog) error {
	return d.repo.DB.Client.WithContext(ctx).Model(log).Create(log).Error
}

func (d *UserDao) WalletCount(ctx context.Context, uid uint) int64 {
	var count int64
	wallet := new(db.UserHfWallet)
	d.repo.DB.Client.WithContext(ctx).Model(wallet).Where("uid=?", uid).Count(&count)
	return count
}

func (d *UserDao) GetReal(ctx context.Context, orderNo string) *db.UserRealName {
	realName := new(db.UserRealName)
	d.repo.DB.Client.WithContext(ctx).Model(realName).Where("order_no=?", orderNo).First(realName)
	return realName
}

func (d *UserDao) GetStraightUserLog(ctx context.Context, uid uint, req *request.UserContributeLog) (int64, *[]entity.StraightUserLog) {
	collection := d.repo.Mongo.Db.Collection("activity_straight_user_log")
	whe := bson.D{
		{"uid", uid},
		{"typeID", req.TypeID},
	}
	count, err := collection.CountDocuments(ctx, whe)
	if err != nil {
		return 0, nil
	}
	var page, pageSize = int64(req.Page), int64(req.PageSize)
	option := options.Find()
	option.SetSort(bson.D{{"addTime", -1}}) //降序
	option.SetSkip((page - 1) * pageSize)
	option.SetLimit(pageSize)
	cur, err := collection.Find(ctx, whe, option)
	if err != nil {
		return 0, nil
	}
	var results []entity.StraightUserLog
	for cur.Next(ctx) {
		var result entity.StraightUserLog
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return 0, nil
		}
		results = append(results, result)
	}
	return count, &results
}

func (d *UserDao) GetBetweenUserLog(ctx context.Context, uid uint, req *request.UserContributeLog) (int64, *[]entity.BetweenUserLog) {
	collection := d.repo.Mongo.Db.Collection("activity_between_user_log")
	whe := bson.D{
		{"uid", uid},
		{"typeID", req.TypeID},
	}
	count, err := collection.CountDocuments(ctx, whe)
	if err != nil {
		return 0, nil
	}
	var page, pageSize = int64(req.Page), int64(req.PageSize)
	option := options.Find()
	option.SetSort(bson.D{{"addTime", -1}}) //降序
	option.SetSkip((page - 1) * pageSize)
	option.SetLimit(pageSize)
	cur, err := collection.Find(ctx, whe, option)
	if err != nil {
		return 0, nil
	}
	var results []entity.BetweenUserLog
	for cur.Next(ctx) {
		var result entity.BetweenUserLog
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return 0, nil
		}
		results = append(results, result)
	}
	return count, &results
}

func (d *UserDao) GetInviteCount(ctx context.Context, uid uint, types int) int64 {
	user := new(db.User)
	var count int64
	_db := d.repo.DB.Client.WithContext(ctx).Model(user).Joins("left join starship_role ON starship_role.uid=starship_user.id")
	if types == 0 {
		_db = _db.Where("starship_user.pid=? AND starship_role.level_id=? AND starship_user.deleted_at IS NULL", uid, types)
	} else {
		_db = _db.Where("starship_user.pid=? AND starship_role.level_id>=? AND starship_user.deleted_at IS NULL", uid, types)
	}
	_db.Count(&count)
	return count
}

func (d *UserDao) GetWalletOfReal(ctx context.Context, uid uint) *db.UserHfWalletHasOneRealName {
	data := new(db.UserHfWalletHasOneRealName)
	d.repo.DB.Client.WithContext(ctx).Model(db.UserHfWallet{}).Where("uid=?", uid).Preload("RealName").First(data)
	return data
}

func (d *UserDao) UpdateUserMap(ctx context.Context, uid uint, user *db.User) error {
	return d.repo.DB.Client.WithContext(ctx).Model(user).Where("id=?", uid).Updates(user).Error
}

func (d *UserDao) UpdateUserCancel(ctx context.Context, uid, status int) error {
	user := new(db.User)
	err := d.repo.DB.Client.WithContext(ctx).Model(user).Where("id=?", uid).Update("status", status).Error
	if err != nil {
		return err
	}
	_, err = d.repo.Mongo.Db.Collection("user").UpdateOne(ctx, bson.D{
		{"uid", uid},
	}, bson.M{"$set": bson.D{
		{"status", status},
	}})
	if err != nil {
		return err
	}
	return nil
}

func (d *UserDao) UserFriends(ctx context.Context, uid uint) *[]db.UserHasOneRole {
	data := new([]db.UserHasOneRole)
	d.repo.DB.Client.WithContext(ctx).Model(db.User{}).Where("pid=?", uid).Preload("Role").Find(data)
	return data
}

func (d *UserDao) MongoUserUpSid(ctx context.Context, uid uint, sid uint64) error {
	collection := d.repo.Mongo.Db.Collection("user")
	_, err := collection.UpdateOne(ctx, bson.D{
		{"uid", uid},
	}, bson.M{
		"$set": bson.M{"sid": sid},
	})
	return err
}

func (d *UserDao) GetNickname(ctx context.Context, uid uint) string {
	var data string
	d.repo.DB.Client.WithContext(ctx).Model(db.Role{}).Where("uid=?", uid).Select("nickname").Scan(&data)
	return data
}

func (d *UserDao) InitProductionInsert(ctx context.Context, uid uint) error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	var err error
	//1.循环赠送槽
	data := new([]db.Production)
	d.repo.DB.Client.WithContext(ctx).Model(data).Where("uid=?", uid).Find(data)
	for _, v := range *data {
		if v.ConsumeTypeID != 0 {
			continue
		}
		production := &db.RoleProduction{
			ProductionID: v.ID,
			UID:          uid,
		}
		err = tx.Model(production).Create(production).Error
		if err != nil {
			break
		}
	}
	if err != nil {
		logs.Error("%v", err)
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func (d *UserDao) GetUserOfRole(ctx context.Context, uid uint) *db.UserHasOneRole {
	data := new(db.UserHasOneRole)
	d.repo.DB.Client.WithContext(ctx).Model(db.User{}).Where("id=?", uid).
		Preload("Role").
		Preload("Role.ChamberMember").
		Preload("Role.ChamberMember.Conf").
		Find(data)
	return data
}

func (d *UserDao) GetVipInfo(ctx context.Context, id uint) *db.VipHasOneReward {
	data := new(db.VipHasOneReward)
	d.repo.DB.Client.WithContext(ctx).Model(&db.Vip{}).
		Where("id=?", id).
		Preload("Types").
		Preload("Reward").
		Preload("Reward.Types").
		Preload("Reward.TypeCard").
		First(data)
	return data
}

func (d *UserDao) MongoGetOrder(ctx context.Context, cancel int, uid uint, id uint) *entity.VipOrder {
	collection := d.repo.Mongo.Db.Collection("vip_order")
	singleResult := collection.FindOne(ctx, bson.D{
		{"uid", uid},
		{"vipID", id},
		{"payStatus", 0},
		{"createTime", bson.D{
			{"$lte", time.Now().Unix() + int64(cancel)},
		}},
	})
	order := new(entity.VipOrder)
	_ = singleResult.Decode(order)
	return order
}

func (d *UserDao) VipCreateOrder(ctx context.Context, order *entity.VipOrder) error {
	collection := d.repo.Mongo.Db.Collection("vip_order")
	_, err := collection.InsertOne(ctx, order)
	if err != nil {
		return fmt.Errorf("购买月卡创建订单失败 err=%v", err)
	}
	return nil
}

func (d *UserDao) MongoGetVipOrderByOrderNo(ctx context.Context, uid uint, orderNo string) *entity.VipOrder {
	collection := d.repo.Mongo.Db.Collection("vip_order")
	singleResult := collection.FindOne(ctx, bson.D{
		{"uid", uid},
		{"orderNo", orderNo},
		{"payStatus", 0},
	})
	order := new(entity.VipOrder)
	_ = singleResult.Decode(order)
	return order
}

func (d *UserDao) VipOrderCancel(ctx context.Context, order *entity.VipOrder) error {
	collection := d.repo.Mongo.Db.Collection("vip_order")
	_, err := collection.UpdateOne(ctx, bson.D{
		{"uid", order.UID},
		{"orderNo", order.OrderNo},
		{"payStatus", 0},
	}, bson.M{
		"$set": bson.M{
			"payStatus":  -1,
			"cancelTime": time.Now().Format(time.DateTime),
		}})
	return err
}

func (d *UserDao) VipOrderPay(ctx context.Context, order *entity.VipOrder, response string) error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	var err error
	//1.修改用户月卡
	role := new(db.Role)
	err = tx.Model(role).Where("uid=? ", order.UID).Updates(map[string]any{
		"is_vip":   true,
		"vip_term": order.VipTerm,
	}).Error
	if err != nil {
		return fmt.Errorf("修改用户月卡失败 err=%v", err)
	}

	//2.修改订单状态为已完成
	order.PayStatus = 1
	order.PayTime = time.Now().Format(time.DateTime)
	order.PayNotify = response
	orderM := _mdb.Db.Collection("vip_order")
	_, err = orderM.UpdateOne(ctx, bson.D{
		{"_id", order.Id},
		{"payStatus", 0},
	}, bson.M{
		"$set": bson.M{
			"payStatus": order.PayStatus,
			"payTime":   order.PayTime,
			"payNotify": order.PayNotify,
		},
	})
	if err != nil {
		tx.Rollback()
		return fmt.Errorf("修改订单数据失败 err=%v", err)
	}
	tx.Commit()
	return nil
}

func (d *UserDao) UpdateRole(ctx context.Context, role *db.Role) error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	err := tx.Model(role).Save(role).Error
	if err != nil {
		return fmt.Errorf("修改用户角色失败 err=%v", err)
	}
	_, err = _mdb.Db.Collection("user").UpdateOne(ctx, bson.D{
		{"uid", role.UID},
	}, bson.M{
		"$set": bson.M{
			"isVIP": role.IsVIP,
		},
	})
	if err != nil {
		tx.Rollback()
		return fmt.Errorf("修改缓存用户角色失败 err=%v", err)
	}
	tx.Commit()
	return nil
}

func (d *UserDao) MongoVipOrderAll(ctx context.Context) *[]entity.VipOrder {
	collection := d.repo.Mongo.Db.Collection("vip_order")
	cur, err := collection.Find(ctx, bson.D{
		{"payStatus", 0},
	})
	if err != nil {
		return nil
	}
	defer cur.Close(ctx)
	var data []entity.VipOrder
	for cur.Next(ctx) {
		var elem entity.VipOrder
		err = cur.Decode(&elem)
		if err != nil {
			return nil
		}
		data = append(data, elem)
	}
	return &data
}

func (d *UserDao) RoleByVip(ctx context.Context) *[]db.Role {
	data := new([]db.Role)
	d.repo.DB.Client.WithContext(ctx).Model(data).Where("is_vip=?", true).Find(data)
	return data
}

func (d *UserDao) GetVipReceiveCount(ctx context.Context, uid uint, id uint, times string) int64 {
	collection := d.repo.Mongo.Db.Collection("vip_receive_log")
	count, _ := collection.CountDocuments(ctx, bson.D{
		{"uid", uid},
		{"vipID", id},
		{"dates", times},
	})
	return count
}

func (d *UserDao) VipReceive(ctx context.Context, receive *entity.VipReceive) error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	mtx, _ := _mdb.Client.StartSession()
	_ = mtx.StartTransaction()
	defer mtx.EndSession(ctx)
	var err error
	//1.添加材料
	for _, v := range receive.VipReward {
		if v.TypeType != 2 {
			err = fmt.Errorf("类型错误")
			break
		}
		material := new(db.WarehouseMaterial)
		_db.Model(material).Where("uid=? AND type_id=?", receive.UID, v.TypeID).First(material)
		var ago, after int64
		var wid uint
		if material == nil || material.ID == 0 {
			ago = 0
			material = &db.WarehouseMaterial{
				UID:    receive.UID,
				TypeID: v.TypeID,
				Num:    v.Num,
			}
			err = tx.Model(material).Create(material).Error
			if err != nil {
				err = fmt.Errorf("添加材料失败 err=%v", err)
				break
			}
			ago = 0
			wid = material.ID
			after = material.Num
		} else {
			err = tx.Model(material).Where("id=?", material.ID).Update("num", gorm.Expr("num + ?", v.Num)).Error
			if err != nil {
				err = fmt.Errorf("添加材料失败 err=%v", err)
				break
			}
			ago = material.Num
			wid = material.ID
			after = material.Num + v.Num
		}
		materialLog := entity.MaterialLog{
			UID:        receive.UID,
			WID:        wid,
			TypeID:     v.TypeID,
			TypeName:   v.TypeName,
			TypeImg:    v.TypeImg,
			TypeModule: v.TypeModule,
			LinkID:     "",
			LinkTable:  "m_vip_receive_log",
			Ago:        ago,
			Num:        v.Num,
			After:      after,
			Remarks:    "会员-领取奖励",
			AddTime:    time.Now().Format(time.DateTime),
		}
		collection := _mdb.Db.Collection("material_log")
		_, err = collection.InsertOne(ctx, materialLog)
		if err != nil {
			err = fmt.Errorf("添加材料日志失败 err=%v", err)
			break
		}
	}
	if err != nil {
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return err
	}
	//2.添加领取记录
	collection := _mdb.Db.Collection("vip_receive_log")
	_, err = collection.InsertOne(ctx, receive)
	if err != nil {
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return fmt.Errorf("添加领取记录失败 err=%v", err)
	}
	_ = mtx.CommitTransaction(ctx)
	tx.Commit()
	return nil
}

func (d *UserDao) GetFleeUsersDiff(ctx context.Context) *[]db.UserHasOneRole {
	data := new([]db.UserHasOneRole)
	d.repo.DB.Client.WithContext(ctx).Model(db.User{}).Where("status=?", 20).
		Preload("Role", func(db *gorm.DB) *gorm.DB {
			return db.Where("is_use=?", false)
		}).
		Preload("Role.ChamberMember").
		Preload("Role.ChamberMember.Conf").
		Find(data)
	return data
}

func (d *UserDao) GetSign(ctx context.Context) *[]db.SignHasOneType {
	data := new([]db.SignHasOneType)
	d.repo.DB.Client.WithContext(ctx).Model(&db.Sign{}).Preload("Types").Find(data)
	return data
}

func (d *UserDao) LastUserSign(ctx context.Context, uid uint) *entity.UserSignLog {
	bettingLog := d.repo.Mongo.Db.Collection("user_sign_log")
	findOptions := options.FindOne().SetSort(bson.M{"signTime": -1})
	var res entity.UserSignLog
	err := bettingLog.FindOne(ctx, bson.D{
		{"uid", uid},
	}, findOptions).Decode(&res)
	if err != nil {
		return nil
	}
	return &res
}

func (d *UserDao) UserSign(ctx context.Context, id uint, log *entity.UserSignLog) *msError.Error {
	//_db := d.repo.DB.Client.WithContext(ctx)
	//tx := _db.Begin()
	//_mdb := d.repo.Mongo
	//mtx, _ := _mdb.Client.StartSession()
	//_ = mtx.StartTransaction()
	//defer mtx.EndSession(ctx)
	//var err error
	////1.添加材料
	//material := new(db.WarehouseMaterial)
	//_db.Model(material).Where("uid=? AND type_id=?", log.UID, log.TypeID).First(material)
	//err = tx.Model(material).Where("id=?", material.ID).Update("num", gorm.Expr("num + ?", log.Num)).Error
	//if err != nil {
	//	logs.Error("[userHandler]用户%d UserSign err:添加材料失败 req=%v,dbErr=%v", log.UID, log, err)
	//	return biz.SqlError
	//}
	////2.添加材料日志
	//materialLog := entity.MaterialLog{
	//	UID:       log.UID,
	//	WID:       material.ID,
	//	TypeID:    material.TypeID,
	//	TypeName:  log.TypeName,
	//	TypeImg:   log.TypeImg,
	//	LinkID:    "",
	//	LinkTable: "m_user_sign_log",
	//	Ago:       material.Num,
	//	Num:       log.Num,
	//	After:     material.Num + log.Num,
	//	Remarks:   "每日签到-领取",
	//	AddTime:   log.SignTime,
	//}
	//collection := _mdb.Db.Collection("material_log")
	//_, err = collection.InsertOne(ctx, materialLog)
	//if err != nil {
	//	logs.Error("[userHandler]用户%d UserSign err:添加材料日志失败 req=%v,dbErr=%v", log.UID, log, err)
	//	tx.Rollback()
	//	_ = mtx.AbortTransaction(ctx)
	//	return biz.SqlError
	//}
	////3.添加签到记录
	//collection = _mdb.Db.Collection("user_sign_log")
	//_, err = collection.InsertOne(ctx, log)
	//if err != nil {
	//	logs.Error("[userHandler]用户%d UserSign err:添加签到记录失败 req=%v,dbErr=%v", log.UID, log, err)
	//	tx.Rollback()
	//	_ = mtx.AbortTransaction(ctx)
	//	return biz.SqlError
	//}
	////4.如果累计签到大于多少则开启赠送
	//var conf string
	//_db.Model(&db.Config{}).Where("sign_day").Select("value").Scan(&conf)
	//signDayConfInt, _ := strconv.Atoi(conf)
	//if log.CumulativeDay >= int64(signDayConfInt) {
	//	role := new(db.Role)
	//	err = tx.Model(role).Where("uid=?", log.UID).Update("is_transfer", true).Error
	//	if err != nil {
	//		logs.Error("[userHandler]用户%d UserSign err:开启赠送失败 req=%v,dbErr=%v", log.UID, log, err)
	//		tx.Rollback()
	//		_ = mtx.AbortTransaction(ctx)
	//		return biz.SqlError
	//	}
	//}
	////if log.CumulativeDay
	//_ = mtx.CommitTransaction(ctx)
	//tx.Commit()
	return nil
}

func (d *UserDao) UserSignReceive(ctx context.Context, sign *entity.UserSignLog, vip *entity.VipReceive) *msError.Error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	var err error
	if sign != nil && sign.UID != 0 { //发放累计签到奖励
		material := new(db.WarehouseMaterial)
		_db.Model(material).Where("uid=? AND type_id=?", sign.UID, sign.TypeID).First(material)
		err = tx.Model(material).Where("id=?", material.ID).Update("num", gorm.Expr("num + ?", sign.Num)).Error
		if err != nil {
			logs.Error("[userHandler]用户%d UserSignReceive err:添加材料失败 req=%v,dbErr=%v", sign.UID, sign, err)
			return biz.SqlError
		}
		//2.添加材料日志
		materialLog := entity.MaterialLog{
			UID:       sign.UID,
			WID:       material.ID,
			TypeID:    material.TypeID,
			TypeName:  sign.TypeName,
			TypeImg:   sign.TypeImg,
			LinkID:    "",
			LinkTable: "m_user_sign_log",
			Ago:       material.Num,
			Num:       sign.Num,
			After:     material.Num + sign.Num,
			Remarks:   "每日签到-领取",
			AddTime:   sign.SignTime,
		}
		collection := d.repo.Mongo.Db.Collection("material_log")
		_, err = collection.InsertOne(ctx, materialLog)
		if err != nil {
			logs.Error("[userHandler]用户%d UserSignReceive err:添加材料日志失败 req=%v,dbErr=%v", sign.UID, sign, err)
			tx.Rollback()
			return biz.SqlError
		}
		//3.添加签到记录
		collection = d.repo.Mongo.Db.Collection("user_sign_log")
		_, err = collection.InsertOne(ctx, sign)
		if err != nil {
			logs.Error("[userHandler]用户%d UserSignReceive err:添加签到记录失败 req=%v,dbErr=%v", sign.UID, sign, err)
			tx.Rollback()
			return biz.SqlError
		}
		//4.如果累计签到大于多少则开启赠送
		var conf string
		_db.Model(&db.Config{}).Where("sign_day").Select("value").Scan(&conf)
		signDayConfInt, _ := strconv.Atoi(conf)
		if sign.CumulativeDay >= int64(signDayConfInt) {
			role := new(db.Role)
			err = tx.Model(role).Where("uid=?", sign.UID).Update("is_transfer", true).Error
			if err != nil {
				logs.Error("[userHandler]用户%d UserSignReceive err:开启赠送失败 req=%v,dbErr=%v", sign.UID, sign, err)
				tx.Rollback()
				return biz.SqlError
			}
		}
	}
	if vip != nil && vip.UID != 0 { //发放vip月卡奖励
		for _, v := range vip.VipReward {
			if v.TypeType != 2 {
				err = fmt.Errorf("类型错误")
				break
			}
			material := new(db.WarehouseMaterial)
			_db.Model(material).Where("uid=? AND type_id=?", vip.UID, v.TypeID).First(material)
			var ago, after int64
			var wid uint
			if material == nil || material.ID == 0 {
				ago = 0
				material = &db.WarehouseMaterial{
					UID:    vip.UID,
					TypeID: v.TypeID,
					Num:    v.Num,
				}
				err = tx.Model(material).Create(material).Error
				if err != nil {
					err = fmt.Errorf("添加材料失败 err=%v", err)
					break
				}
				ago = 0
				wid = material.ID
				after = material.Num
			} else {
				err = tx.Model(material).Where("id=?", material.ID).Update("num", gorm.Expr("num + ?", v.Num)).Error
				if err != nil {
					err = fmt.Errorf("添加材料失败 err=%v", err)
					break
				}
				ago = material.Num
				wid = material.ID
				after = material.Num + v.Num
			}
			materialLog := entity.MaterialLog{
				UID:        vip.UID,
				WID:        wid,
				TypeID:     v.TypeID,
				TypeName:   v.TypeName,
				TypeImg:    v.TypeImg,
				TypeModule: v.TypeModule,
				LinkID:     "",
				LinkTable:  "m_vip_receive_log",
				Ago:        ago,
				Num:        v.Num,
				After:      after,
				Remarks:    "月卡-领取",
				AddTime:    time.Now().Format(time.DateTime),
			}
			collection := d.repo.Mongo.Db.Collection("material_log")
			_, err = collection.InsertOne(ctx, materialLog)
			if err != nil {
				err = fmt.Errorf("添加材料日志失败 err=%v", err)
				break
			}
		}
		if err != nil {
			logs.Error("[userHandler]用户%d UserSignReceive req=%v,dbErr=%v", vip.UID, vip, err)
			tx.Rollback()
			return biz.SqlError
		}
		//2.添加领取记录
		collection := d.repo.Mongo.Db.Collection("vip_receive_log")
		_, err = collection.InsertOne(ctx, vip)
		if err != nil {
			logs.Error("[userHandler]用户%d UserSignReceive err=添加领取月卡失败,req=%v,dbErr=%v", vip.UID, vip, err)
			tx.Rollback()
			return biz.SqlError
		}
	}
	tx.Commit()
	return nil
}

func (d *UserDao) GetMongoUserSignInfo(ctx context.Context, uid uint, round int64, id uint) *entity.UserSignLog {
	collection := d.repo.Mongo.Db.Collection("user_sign_log")
	var info entity.UserSignLog
	err := collection.FindOne(ctx, bson.D{
		{"uid", uid},
		{"round", round},
		{"signID", id},
	}).Decode(&info)
	if err != nil {
		return nil
	}
	return &info
}

func (d *UserDao) AddAlipayNotifyLog(ctx context.Context, log *entity.UserAlipayNotifyLog) error {
	collection := d.repo.Mongo.Db.Collection("alipay_notify_log")
	_, err := collection.InsertOne(ctx, log)
	return err
}

func (d *UserDao) MonthlyCardAdd(ctx context.Context, uid uint, info *db.VipHasOneReward, material *db.WarehouseMaterialHasOneType, priceOne *db.VipPriceHasOneType) *msError.Error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	var err error
	//1.扣除材料
	if material != nil && material.ID != 0 {
		err = tx.Model(&db.WarehouseMaterial{}).Where("id=?", material.ID).Update("num", gorm.Expr("num - ?", priceOne.ConsumeNum)).Error
		if err != nil {
			logs.Error("[userHandler]用户%d MonthlyCardOpen err:扣除材料失败 req=%v,dbErr=%v", uid, priceOne, err)
			return biz.SqlError
		}
		materialLog := &entity.MaterialLog{
			UID:        uid,
			WID:        material.ID,
			TypeID:     material.TypeID,
			TypeName:   material.Types.Name,
			TypeImg:    material.Types.Img,
			TypeModule: material.Types.Module,
			LinkID:     "",
			LinkTable:  "m_vip_order",
			Ago:        material.Num,
			Num:        -priceOne.ConsumeNum,
			After:      material.Num - priceOne.ConsumeNum,
			Remarks:    "月卡-购买",
			AddTime:    time.Now().Format(time.DateTime),
		}
		_, err = _mdb.Db.Collection("material_log").InsertOne(ctx, materialLog)
		if err != nil {
			logs.Error("[userHandler]用户%d MonthlyCardOpen err:添加材料日志失败 req=%v,dbErr=%v", uid, info, err)
			tx.Rollback()
			return biz.SqlError
		}
	}
	//2.修改用户月卡
	role := new(db.Role)
	err = tx.Model(role).Where("uid=? ", uid).Updates(map[string]any{
		"is_vip":   true,
		"vip_term": info.Term,
	}).Error
	if err != nil {
		logs.Error("[userHandler]用户%d MonthlyCardOpen err:修改用户月卡失败 req=%v,dbErr=%v", uid, info, err)
		tx.Rollback()
		return biz.SqlError
	}
	//3.添加月卡记录
	var payTime string
	if info.Type != 1 {
		payTime = time.Now().Format(time.DateTime)
	}
	order := &entity.VipOrder{
		UID:           uid,
		VipID:         info.ID,
		Type:          info.Type,
		OrderNo:       utils.GenOrderNumber("VIP"),
		VipName:       info.Name,
		VipPrice:      info.Price,
		VipTerm:       info.Term,
		PayStatus:     1,
		CreateTime:    time.Now().Unix(),
		PayTime:       payTime,
		PayNotify:     "",
		ConsumeTypeID: priceOne.ConsumeTypeID,
		ConsumeName:   priceOne.Types.Name,
		ConsumeImg:    priceOne.Types.Img,
		ConsumeNum:    priceOne.ConsumeNum,
	}
	_, err = _mdb.Db.Collection("vip_order").InsertOne(ctx, order)
	if err != nil {
		logs.Error("[userHandler]用户%d MonthlyCardOpen err:添加月卡订单记录失败 req=%v,dbErr=%v", uid, info, err)
		tx.Rollback()
		return biz.SqlError
	}
	//4.修改mongo用户信息
	collection := d.repo.Mongo.Db.Collection("user")
	_, err = collection.UpdateOne(ctx, bson.D{
		{"uid", uid},
	}, bson.D{
		{"$set", bson.D{
			{"isVIP", true},
		}},
	})
	//5.添加月卡购买赠送卡牌
	var vipReward []entity.VipReward
	for _, v := range info.Reward {
		if v.Types.Type != 1 {
			continue
		}
		card := &db.WarehouseCard{
			UID:         uid,
			TypeID:      v.TypeID,
			TypeCardID:  v.TypeCardID,
			Num:         v.TypeCard.TotalOutput,
			Rate:        v.Rate,
			IsAbandon:   false,
			IsUse:       false,
			IsNew:       true,
			IsFreeze:    false,
			IsChain:     0,
			Hax:         nil,
			OperationID: "",
			TokenID:     nil,
		}
		err = tx.Model(card).Create(card).Error
		if err != nil {
			err = fmt.Errorf("[userHandler]用户%d MonthlyCardOpen err:赠送卡牌失败 req=%v,dbErr=%v", uid, info.Reward, err)
			break
		}
		//NFT添加一个tokenID
		widLen := len(fmt.Sprintf("%d", card.ID))
		var widStr string
		if widLen < 8 {
			for i := 0; i < 8-widLen; i++ {
				widStr += "0"
			}
		}
		widStr += fmt.Sprintf("%d", card.ID)
		tokenID := fmt.Sprintf("S%v", widStr)
		card.TokenID = &tokenID
		err = tx.Save(card).Error
		if err != nil {
			err = fmt.Errorf("[userHandler]用户%d MonthlyCardOpen err:添加tokenID失败 req=%v,dbErr=%v", uid, info.Reward, err)
			break
		}
		vipReward = append(vipReward, entity.VipReward{
			TypeID:     v.TypeID,
			TypeName:   v.Types.Name,
			TypeImg:    v.Types.Img,
			TypeModule: v.Types.Module,
			TypeType:   v.Types.Type,
			Num:        v.Num,
		})
		// TODO 上链
		//go d.base.TimingObtainHax(uid, card.ID)
	}
	if err != nil {
		logs.Error("%v", err)
		tx.Rollback()
		return biz.SqlError
	}
	//6.添加赠送卡牌记录
	vipReceive := entity.VipReceive{
		UID:         uid,
		VipID:       info.ID,
		VipName:     info.Name,
		VipReward:   vipReward,
		Dates:       utils.TimeOrDateAsYear(0, "", "Y-m-d"),
		ReceiveTime: time.Now().Format(time.DateTime),
	}
	_, err = _mdb.Db.Collection("vip_receive_log").InsertOne(ctx, vipReceive)
	if err != nil {
		logs.Error("[userHandler]用户%d MonthlyCardOpen err:添加赠送卡牌记录失败 req=%v,dbErr=%v", uid, info.Reward, err)
		tx.Rollback()
		return biz.SqlError
	}
	tx.Commit()
	return nil
}

func (d *UserDao) GetMongoVipReceiveCount(ctx context.Context, uid uint) int64 {
	collection := d.repo.Mongo.Db.Collection("vip_receive_log")
	count, _ := collection.CountDocuments(ctx, bson.D{
		{"uid", uid},
		{"dates", utils.TimeOrDateAsYear(0, "", "Y-m-d")},
	})
	return count
}

func (d *UserDao) GetInviteCodeByUid(ctx context.Context, inviteCode int64) uint {
	var uid uint
	d.repo.DB.Client.WithContext(ctx).Model(&db.User{}).Where("invite_code=?", inviteCode).Select("id").Scan(&uid)
	return uid
}

func (d *UserDao) MongoGetLastUserRewardSum(ctx context.Context, uid uint) int64 {
	killLog := d.repo.Mongo.Db.Collection("goods_last_user_reward_log")
	aggregate, _ := killLog.Aggregate(ctx, mongo.Pipeline{bson.D{
		{"$match", bson.D{
			{"pid", uid},
			{"isReceive", false},
		}},
	}, bson.D{
		{"$group", bson.D{
			{"_id", nil},
			{"total", bson.D{
				{"$sum", "$reward"},
			}},
		}},
	}})
	var showsWithInfo []map[string]interface{}
	_ = aggregate.All(context.TODO(), &showsWithInfo)
	//总杀死房间的游戏币数
	var killNum int64
	if len(showsWithInfo) > 0 {
		killNum = showsWithInfo[0]["total"].(int64)
	}
	return killNum
}

func (d *UserDao) MongoGetLastUserReward(ctx context.Context, uid uint, req *request.PageMsg) (int64, *[]entity.GoodsLastUserReward) {
	collection := d.repo.Mongo.Db.Collection("goods_last_user_reward_log")
	whe := bson.D{
		{"pid", uid},
	}
	count, err := collection.CountDocuments(ctx, whe)
	if err != nil {
		return 0, nil
	}
	var page, pageSize = int64(req.Page), int64(req.PageSize)
	option := options.Find()
	option.SetSort(bson.D{{"addTime", -1}}) //降序
	option.SetSkip((page - 1) * pageSize)
	option.SetLimit(pageSize)

	cur, err := collection.Find(ctx, whe, option)
	if err != nil {
		return 0, nil
	}
	var results []entity.GoodsLastUserReward
	for cur.Next(ctx) {
		var result entity.GoodsLastUserReward
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return 0, nil
		}
		results = append(results, result)
	}
	return count, &results
}

func (d *UserDao) MongoGetLastUserNotReward(ctx context.Context, uid uint) *[]entity.GoodsLastUserReward {
	collection := d.repo.Mongo.Db.Collection("goods_last_user_reward_log")
	whe := bson.D{
		{"pid", uid},
		{"isReceive", false},
	}
	cur, err := collection.Find(ctx, whe)
	if err != nil {
		return nil
	}
	var results []entity.GoodsLastUserReward
	for cur.Next(ctx) {
		var result entity.GoodsLastUserReward
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return nil
		}
		results = append(results, result)
	}
	return &results
}

func (d *UserDao) PullActivityReceive(ctx context.Context, uid uint) *msError.Error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	var err error
	//1.获取未领取的数据
	lastUser := d.MongoGetLastUserNotReward(ctx, uid)
	materialLogM := d.repo.Mongo.Db.Collection("material_log")
	lastUserRewardLogM := d.repo.Mongo.Db.Collection("goods_last_user_reward_log")
	times := time.Now().Format(time.DateTime)
	for _, v := range *lastUser {
		if v.IsReceive {
			continue
		}
		//2.添加奖励
		material := new(db.WarehouseMaterial)
		materialType := new(db.WarehouseMaterialHasOneType)
		_db.Model(material).Where("uid=? AND type_id", uid, v.RewardTypeID).Preload("Types").First(materialType)
		err = tx.Model(material).Where("id=?", materialType.ID).Update("num", gorm.Expr("num + ?", v.Reward)).Error
		if err != nil {
			err = fmt.Errorf("[userHandler]用户%d PullActivityReceive err:领取奖励失败,res=%v,dbErr=%v", uid, v, err)
			break
		}
		//3.添加奖励日志
		materialLog := &entity.MaterialLog{
			UID:        uid,
			WID:        materialType.ID,
			TypeID:     materialType.TypeID,
			TypeName:   materialType.Types.Name,
			TypeImg:    materialType.Types.Img,
			TypeModule: materialType.Types.Module,
			LinkID:     fmt.Sprintf("%v", v.Id),
			LinkTable:  "m_goods_last_user_reward_log",
			Ago:        materialType.Num,
			Num:        v.Reward,
			After:      materialType.Num + v.Reward,
			Remarks:    "拉新活动-领取奖励",
			AddTime:    times,
		}
		_, err = materialLogM.InsertOne(ctx, materialLog)
		if err != nil {
			err = fmt.Errorf("[userHandler]用户%d PullActivityReceive err:添加奖励日志失败,res=%v,dbErr=%v", uid, v, err)
			break
		}
		//4.修改状态为已领取
		_, err = lastUserRewardLogM.UpdateOne(ctx, bson.D{
			{"_id", v.Id},
			{"isReceive", false},
		}, bson.M{"$set": bson.D{
			{"isReceive", true},
			{"receiveTime", times},
		}})
		if err != nil {
			err = fmt.Errorf("[userHandler]用户%d PullActivityReceive err:修改状态为已领取失败,res=%v,dbErr=%v", uid, v, err)
			break
		}
	}
	if err != nil {
		logs.Error("%v", err)
		tx.Rollback()
		return biz.SqlError
	}
	tx.Commit()
	return nil
}

func (d *UserDao) GetStraightUserLogList(ctx context.Context, uid uint, req request.PageMsg) (int64, *[]entity.StraightUserLog) {
	collection := d.repo.Mongo.Db.Collection("activity_straight_user_log")
	whe := bson.D{
		{"uid", uid},
	}
	count, err := collection.CountDocuments(ctx, whe)
	if err != nil {
		return 0, nil
	}
	var page, pageSize = int64(req.Page), int64(req.PageSize)
	option := options.Find()
	option.SetSort(bson.D{{"addTime", -1}}) //降序
	option.SetSkip((page - 1) * pageSize)
	option.SetLimit(pageSize)
	cur, err := collection.Find(ctx, whe, option)
	if err != nil {
		return 0, nil
	}
	var results []entity.StraightUserLog
	for cur.Next(ctx) {
		var result entity.StraightUserLog
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return 0, nil
		}
		results = append(results, result)
	}
	return count, &results
}
func (d *UserDao) GetStraightUserLogAll(ctx context.Context, uid uint) *[]entity.StraightUserLog {
	collection := d.repo.Mongo.Db.Collection("activity_straight_user_log")
	whe := bson.D{
		{"uid", uid},
		{"isReceive", false},
	}
	cur, err := collection.Find(ctx, whe)
	if err != nil {
		return nil
	}
	var results []entity.StraightUserLog
	for cur.Next(ctx) {
		var result entity.StraightUserLog
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return nil
		}
		results = append(results, result)
	}
	return &results
}

func (d *UserDao) GetBetweenUserLogList(ctx context.Context, uid uint, req request.PageMsg) (int64, *[]entity.BetweenUserLog) {
	collection := d.repo.Mongo.Db.Collection("activity_between_user_log")
	whe := bson.D{
		{"uid", uid},
	}
	count, err := collection.CountDocuments(ctx, whe)
	if err != nil {
		return 0, nil
	}
	var page, pageSize = int64(req.Page), int64(req.PageSize)
	option := options.Find()
	option.SetSort(bson.D{{"addTime", -1}}) //降序
	option.SetSkip((page - 1) * pageSize)
	option.SetLimit(pageSize)
	cur, err := collection.Find(ctx, whe, option)
	if err != nil {
		return 0, nil
	}
	var results []entity.BetweenUserLog
	for cur.Next(ctx) {
		var result entity.BetweenUserLog
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return 0, nil
		}
		results = append(results, result)
	}
	return count, &results
}
func (d *UserDao) GetBetweenUserLogAll(ctx context.Context, uid uint) *[]entity.BetweenUserLog {
	collection := d.repo.Mongo.Db.Collection("activity_between_user_log")
	whe := bson.D{
		{"uid", uid},
		{"isReceive", false},
	}
	cur, err := collection.Find(ctx, whe)
	if err != nil {
		return nil
	}
	var results []entity.BetweenUserLog
	for cur.Next(ctx) {
		var result entity.BetweenUserLog
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return nil
		}
		results = append(results, result)
	}
	return &results
}

func (d *UserDao) PullActivityContributionReceive(ctx context.Context, uid uint, types int) *msError.Error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	var err error
	//1.获取未领取的数据
	materialLogM := d.repo.Mongo.Db.Collection("material_log")
	times := time.Now().Format(time.DateTime)
	switch types {
	case 1:
		straightUser := d.GetStraightUserLogAll(ctx, uid)
		straightUserLogM := d.repo.Mongo.Db.Collection("activity_straight_user_log")
		//领取直推收益
		for _, v := range *straightUser {
			if v.IsReceive {
				continue
			}
			//2.添加奖励
			material := new(db.WarehouseMaterial)
			materialType := new(db.WarehouseMaterialHasOneType)
			_db.Model(material).Where("uid=? AND type_id", v.UID, v.TypeID).Preload("Types").First(materialType)
			err = tx.Model(material).Where("id=?", materialType.ID).Update("num", gorm.Expr("num + ?", v.Num)).Error
			if err != nil {
				err = fmt.Errorf("[userHandler]用户%d PullActivityContributionReceive err:领取奖励失败,res=%v,dbErr=%v", v.UID, v, err)
				break
			}
			//3.添加奖励日志
			materialLog := &entity.MaterialLog{
				UID:        v.UID,
				WID:        materialType.ID,
				TypeID:     materialType.TypeID,
				TypeName:   materialType.Types.Name,
				TypeImg:    materialType.Types.Img,
				TypeModule: materialType.Types.Module,
				LinkID:     fmt.Sprintf("%v", v.Id),
				LinkTable:  "m_goods_last_user_reward_log",
				Ago:        materialType.Num,
				Num:        v.Num,
				After:      materialType.Num + v.Num,
				Remarks:    "拉新活动-领取直推贡献收益",
				AddTime:    times,
			}
			_, err = materialLogM.InsertOne(ctx, materialLog)
			if err != nil {
				err = fmt.Errorf("[userHandler]用户%d PullActivityContributionReceive err:添加奖励日志失败,res=%v,dbErr=%v", v.UID, v, err)
				break
			}
			//4.修改状态为已领取
			_, err = straightUserLogM.UpdateOne(ctx, bson.D{
				{"_id", v.Id},
				{"isReceive", false},
			}, bson.M{"$set": bson.D{
				{"isReceive", true},
				{"receiveTime", times},
			}})
			if err != nil {
				err = fmt.Errorf("[userHandler]用户%d PullActivityContributionReceive err:修改状态为已领取失败,res=%v,dbErr=%v", v.UID, v, err)
				break
			}
		}
		if err != nil {
			logs.Error("%v", err)
			tx.Rollback()
			return biz.SqlError
		}
		break
	case 2:
		betweenUserUser := d.GetBetweenUserLogAll(ctx, uid)
		betweenUserLogM := d.repo.Mongo.Db.Collection("activity_between_user_log")
		//领取间推收益
		for _, v := range *betweenUserUser {
			if v.IsReceive {
				continue
			}
			//2.添加奖励
			material := new(db.WarehouseMaterial)
			materialType := new(db.WarehouseMaterialHasOneType)
			_db.Model(material).Where("uid=? AND type_id", v.UID, v.TypeID).Preload("Types").First(materialType)
			err = tx.Model(material).Where("id=?", materialType.ID).Update("num", gorm.Expr("num + ?", v.Num)).Error
			if err != nil {
				err = fmt.Errorf("[userHandler]用户%d PullActivityContributionReceive err:领取奖励失败,res=%v,dbErr=%v", v.UID, v, err)
				break
			}
			//3.添加奖励日志
			materialLog := &entity.MaterialLog{
				UID:        v.UID,
				WID:        materialType.ID,
				TypeID:     materialType.TypeID,
				TypeName:   materialType.Types.Name,
				TypeImg:    materialType.Types.Img,
				TypeModule: materialType.Types.Module,
				LinkID:     fmt.Sprintf("%v", v.Id),
				LinkTable:  "m_goods_last_user_reward_log",
				Ago:        materialType.Num,
				Num:        v.Num,
				After:      materialType.Num + v.Num,
				Remarks:    "拉新活动-领取间推贡献收益",
				AddTime:    times,
			}
			_, err = materialLogM.InsertOne(ctx, materialLog)
			if err != nil {
				err = fmt.Errorf("[userHandler]用户%d PullActivityContributionReceive err:添加奖励日志失败,res=%v,dbErr=%v", v.UID, v, err)
				break
			}
			//4.修改状态为已领取
			_, err = betweenUserLogM.UpdateOne(ctx, bson.D{
				{"_id", v.Id},
				{"isReceive", false},
			}, bson.M{"$set": bson.D{
				{"isReceive", true},
				{"receiveTime", times},
			}})
			if err != nil {
				err = fmt.Errorf("[userHandler]用户%d PullActivityContributionReceive err:修改状态为已领取失败,res=%v,dbErr=%v", v.UID, v, err)
				break
			}
		}
		if err != nil {
			logs.Error("%v", err)
			tx.Rollback()
			return biz.SqlError
		}
		break
	default:
		logs.Error("[userHandler]用户%d PullActivityContributionReceive err:types参数错误 1直推|2间推 传入参数%d", uid, types)
		return biz.RequestDataError
	}
	tx.Commit()
	return nil
}

func (d *UserDao) PullActivityFriends(ctx context.Context, uid uint, req *request.PageMsg) (int64, *[]db.UserHasOneRole) {
	data := new([]db.UserHasOneRole)
	var count int64
	_db := d.repo.DB.Client.WithContext(ctx).Model(&db.User{}).Where("pid=?", uid)
	_db.Count(&count)
	_db.Order("id desc").Preload("Role").Scopes(db.Paginate(req.Page, req.PageSize)).Find(data)
	return count, data
}

func (d *UserDao) ChamberList(ctx context.Context, page int, size int) (int64, *[]db.ChamberHasManyMemberAsUser) {
	data := new([]db.ChamberHasManyMemberAsUser)
	var count int64
	_db := d.repo.DB.Client.WithContext(ctx).Model(&db.Chamber{})
	_db.Count(&count)
	_db.Order("id desc").
		Preload("Members").
		Preload("Members.Level").
		Preload("Members.User").
		Preload("Members.User.Role").
		Preload("Role").
		Scopes(db.Paginate(page, size)).Find(data)
	return count, data
}

func (d *UserDao) ChamberMember(ctx context.Context, id uint, msg request.PageMsg) (int64, *[]db.ChamberMemberHasOneLevelAsUser) {
	data := new([]db.ChamberMemberHasOneLevelAsUser)
	var count int64
	_db := d.repo.DB.Client.WithContext(ctx).Model(&db.ChamberMember{}).Where("chamber_id=?", id)
	_db.Count(&count)
	_db.Order("level_id Asc").
		Preload("Conf").
		Preload("User").
		Preload("User.Role").
		Scopes(db.Paginate(msg.Page, msg.PageSize)).Find(data)
	return count, data
}

func (d *UserDao) GetChamberMemberByPID(ctx context.Context, pid uint) uint {
	var uid uint
	d.repo.DB.Client.WithContext(ctx).Model(&db.ChamberMember{}).Where("id=?", pid).Select("uid").Scan(&uid)
	return uid
}

func (d *UserDao) GetLotteryList(ctx context.Context) *[]db.LotteryHasOneType {
	data := new([]db.LotteryHasOneType)
	d.repo.DB.Client.WithContext(ctx).Model(&db.Lottery{}).Preload("Types").Find(data)
	return data
}

func (d *UserDao) Lottery(ctx context.Context, uid uint, types *db.Type, consumeNum int64) (*db.LotteryHasOneType, *msError.Error) {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	var err error
	//1.扣除材料
	material := new(db.WarehouseMaterial)
	_db.Model(material).Where("uid=? AND type_id=?", uid, types.ID).First(material)
	if material == nil || material.ID == 0 {
		logs.Error("[userHandler]用户%d Lottery err:材料不足 res=%v", uid, types)
		return nil, biz.GoodsPayError
	}
	if material.Num < consumeNum {
		logs.Error("[userHandler]用户%d Lottery err:材料不足 res=%v", uid, types)
		return nil, biz.GoodsPayError
	}
	if err = tx.Model(material).Where("id=?", material.ID).Update("num", gorm.Expr("num - ?", consumeNum)).Error; err != nil {
		logs.Error("[userHandler]用户%d Lottery err:扣除材料失败 res=%v,dbErr=%v", uid, types, err)
		return nil, biz.SqlError
	}
	//2.随机奖品
	rands := utils.Random(1, 10000)
	lottery := new(db.LotteryHasOneType)
	_db.Model(&db.Lottery{}).Where("min_rate<=? AND max_rate>=?", rands, rands).Preload("Types").First(lottery)
	if lottery == nil || lottery.ID == 0 {
		logs.Error("[userHandler]用户%d Lottery err:随机奖品失败 res=%v", uid, types)
		tx.Rollback()
		return nil, biz.SqlError
	}
	//3.添加材料日志
	materialLog := &entity.MaterialLog{
		UID:        uid,
		WID:        material.ID,
		TypeID:     types.ID,
		TypeName:   types.Name,
		TypeImg:    types.Img,
		TypeModule: types.Module,
		LinkID:     fmt.Sprintf("%d", rands),
		LinkTable:  "m_user_lottery_log",
		Ago:        material.Num,
		Num:        -consumeNum,
		After:      material.Num - consumeNum,
		Remarks:    "抽奖",
		AddTime:    time.Now().Format(time.DateTime),
	}
	collection := d.repo.Mongo.Db.Collection("material_log")
	_, err = collection.InsertOne(ctx, materialLog)
	if err != nil {
		logs.Error("[userHandler]用户%d Lottery err:添加材料日志失败 res=%v,dbErr=%v", uid, types, err)
		tx.Rollback()
		return nil, biz.SqlError
	}
	//4.不是实物，添加奖励
	if !lottery.Type {
		material = new(db.WarehouseMaterial)
		_db.Model(material).Where("uid=? AND type_id=?", uid, lottery.TypeID).First(material)
		var ago, after int64
		var wid = material.ID
		if material == nil || material.ID == 0 {
			material = &db.WarehouseMaterial{
				UID:    uid,
				TypeID: lottery.TypeID,
				Num:    lottery.Num,
			}
			err = tx.Model(material).Create(material).Error
			after = lottery.Num
			wid = material.ID
		} else {
			err = tx.Model(material).Where("id=?", material.ID).Update("num", gorm.Expr("num + ?", lottery.Num)).Error
			ago = material.Num
			after = material.Num + lottery.Num
		}
		if err != nil {
			logs.Error("[userHandler]用户%d Lottery err:添加奖励失败 res=%v,dbErr=%v", uid, types, err)
			tx.Rollback()
			return nil, biz.SqlError
		}
		//5.添加奖励日志
		materialLog = &entity.MaterialLog{
			UID:        uid,
			WID:        wid,
			TypeID:     lottery.TypeID,
			TypeName:   lottery.Types.Name,
			TypeImg:    lottery.Types.Img,
			TypeModule: lottery.Types.Module,
			LinkID:     "",
			LinkTable:  "m_user_lottery_log",
			Ago:        ago,
			Num:        lottery.Num,
			After:      after,
			Remarks:    "抽奖-获得奖励",
			AddTime:    time.Now().Format(time.DateTime),
		}
		_, err = collection.InsertOne(ctx, materialLog)
		if err != nil {
			logs.Error("[userHandler]用户%d Lottery err:添加材料日志失败 res=%v,dbErr=%v", uid, types, err)
			tx.Rollback()
			return nil, biz.SqlError
		}
	}
	//6.添加抽取记录
	var name, img = lottery.Name, lottery.Img
	if !lottery.Type {
		name, img = lottery.Types.Name, lottery.Types.Img
	}
	log := &entity.UserLottery{
		UID:             uid,
		ConsumeTypeID:   types.ID,
		ConsumeTypeName: types.Name,
		ConsumeTypeImg:  types.Img,
		ConsumeNum:      consumeNum,
		LotteryRand:     rands,
		LotteryID:       lottery.ID,
		LotteryType:     lottery.Type,
		LotteryName:     name,
		LotteryImg:      img,
		LotteryNum:      lottery.Num,
		AddTime:         time.Now().Format(time.DateTime),
	}
	lotteryLog := d.repo.Mongo.Db.Collection("user_lottery_log")
	_, err = lotteryLog.InsertOne(ctx, log)
	if err != nil {
		logs.Error("[userHandler]用户%d Lottery err:添加抽取记录失败 res=%v,dbErr=%v", uid, types, err)
		tx.Rollback()
		return nil, biz.SqlError
	}

	tx.Commit()
	return lottery, nil
}

func (d *UserDao) LotteryLogAll(ctx context.Context, size int64) *[]entity.UserLottery {
	collection := d.repo.Mongo.Db.Collection("user_lottery_log")
	whe := bson.D{}
	var page, pageSize = int64(1), size
	option := options.Find()
	option.SetSort(bson.D{{"addTime", -1}}) //降序
	option.SetSkip((page - 1) * pageSize)
	option.SetLimit(pageSize)
	cur, err := collection.Find(ctx, whe, option)
	if err != nil {
		return nil
	}
	var results []entity.UserLottery
	for cur.Next(ctx) {
		var result entity.UserLottery
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return nil
		}
		results = append(results, result)
	}
	return &results
}

func (d *UserDao) Customer(ctx context.Context) *[]db.CustomerService {
	data := new([]db.CustomerService)
	d.repo.DB.Client.WithContext(ctx).Model(data).Find(data)
	return data
}

func (d *UserDao) SetTransactionPassword(ctx context.Context, uid uint, password string) *msError.Error {
	user := new(db.User)
	err := d.repo.DB.Client.WithContext(ctx).Model(user).Where("id=?", uid).Update("transaction_password", password).Error
	if err != nil {
		logs.Error("[userHandler]SetTransactionPassword err:设置交易密码失败 res=%v,dbErr=%v", uid, err)
		return biz.SqlError
	}
	_, err = d.repo.Mongo.Db.Collection("user").UpdateOne(ctx, bson.D{{"uid", uid}}, bson.D{{"$set", bson.D{{"isTranPwd", true}}}})
	if err != nil {
		logs.Error("[userHandler]SetTransactionPassword err:设置交易密码失败 res=%v,dbErr=%v", uid, err)
		return biz.SqlError
	}
	return nil
}

func (d *UserDao) UpRoleIsUse(ctx context.Context, uid uint) {
	d.repo.DB.Client.WithContext(ctx).Model(&db.Role{}).Where("uid=?", uid).Update("is_use", true)
}

func (d *UserDao) GetVipOrderCount(ctx context.Context) int64 {
	count, _ := d.repo.Mongo.Db.Collection("vip_order").CountDocuments(ctx, bson.D{})
	return count
}

func (d *UserDao) GetVipPrice(ctx context.Context, count int64) *db.VipPriceHasOneType {
	data := new(db.VipPriceHasOneType)
	d.repo.DB.Client.WithContext(ctx).Table(data.TableName()).Where("num>?", count).Preload("Types").First(data)
	return data
}

func NewUserDao(m *repo.Manager) *UserDao {
	return &UserDao{
		repo: m,
		base: NewBaseDao(m),
	}
}
